// 自动检测任务与英雄属性
import {UnitController} from "../controller/UnitController";
import {TaskController} from "../controller/TaskController";
import {
    BroadcastRequest,
    BroadcastType,
    ControllerNo,
    GuiControllerOpt,
    GuiId,
    TimeControllerOpt
} from "../controller/model/ControllerOpt";
import {ConfigKey, ResumeType} from "../constant/ConfigConstant";
import {TimeController} from "../controller/TimeController";
import {GlobalEnv} from "../utils/GlobalEnv";

import {StoreController} from "../controller/StoreController";
import {GuiController, OptType} from "../controller/GuiController";
import Configer from "../frame/apiModel/config/Configer";
import {FinalKey} from "../constant/FinalConstant";
import {ControllerBroadcast} from "../controller/ControllerBroadcast";
import MathUtil from "../frame/codeAdapter/MathUtil";
import {DataRouterUtil} from "../utils/router/DataRouterUtil";
import {UnitJson} from "../frame/apiModel/model/StoreJson";
import {PlayerFactory} from "../frame/PlayerFactory";
import {PlayerDataKey, UnitDataKey} from "../frame/dataSource/DataSource";
import {UnitModel} from "../frame/apiModel/adapterModel/model3/UnitModel";
import {PlayerModel} from "../frame/apiModel/adapterModel/model4/PlayerModel";
import {Logger} from "../frame/apiModel/config/Logger";
import {OrderStr} from "../type/Type";
import {LocModel} from "../frame/apiModel/base/LocModel";
import {ModelFactory} from "../frame/apiModel/adapterModel/model5/ModelFactory";
import {CodeUtil} from "../frame/codeAdapter/CodeUtil";
import {AbilityController} from "../controller/AbilityController";
import {GameLoseType, GameWinType} from "../frame/dataSource/DataModel";
import {TriggerFactory} from "../frame/TriggerFactory";


export function autoCheckTrigger() {
    const foreverPeriodic = Configer.getFinal(FinalKey.foreverPeriodic) as number;


    // 刷新ui  1秒一次
    const ReactClearFunFast = function () {
        reflushShareBoss();
        reflushUIPanelFast();
    }
    const ReactClearFunFastOpt = new TimeControllerOpt(undefined, ReactClearFunFast, foreverPeriodic);
    TimeController.getInstance().startTimer({time: 0.01, opt: ReactClearFunFastOpt});

    const ReactClearFunSlow = function () {
        reflushUIPanelSlow();
    }
    const ReactClearOpt1 = new TimeControllerOpt(undefined, ReactClearFunSlow, foreverPeriodic);
    TimeController.getInstance().startTimer({time: 1, opt: ReactClearOpt1});


    const clearSyncFun = function () {
        TriggerFactory.exeSyncDatas();
    }
    const clearSyncOpt = new TimeControllerOpt(undefined, clearSyncFun, foreverPeriodic);
    TimeController.getInstance().startTimer({time: 0.1, opt: clearSyncOpt});


    // 删除垃圾物品
    const clearModelCallBack = function () {
        ModelFactory.getInstance().mapAllItemModelClear();
    }
    const clearModelTimerOpt = new TimeControllerOpt(undefined, clearModelCallBack, foreverPeriodic);
    TimeController.getInstance().startTimer({time: 10, opt: clearModelTimerOpt});

    // 刷新怪物路径
    let reflushPath = Configer.getConfig(ConfigKey.reflushPath);
    const reflushPathCallBack = function () {
        UnitController.getInstance().reflushPath();
    }
    const reflushPathTimerOpt = new TimeControllerOpt(undefined, reflushPathCallBack, foreverPeriodic);
    TimeController.getInstance().startTimer({time: reflushPath, opt: reflushPathTimerOpt});

    // 刷新怪物仇恨目标
    // let reflushHatred = Configer.getConfig(ConfigKey.reflushHatred);
    // const reflushHatredCallBack = function () {
    //     UnitController.getInstance().reflushHatred();
    // }
    // const reflushHatredTimerOpt = new TimeControllerOpt(undefined, reflushHatredCallBack, foreverPeriodic);
    // TimeController.getInstance().startTimer({time: reflushHatred, opt: reflushHatredTimerOpt});


    // // 技能状态刷新倒计时
    // const reflushAbilityCallBack = function () {
    //     UnitController.getInstance().reflushPath();
    // }
    // const reflushAbilityTimerOpt = new TimeControllerOpt(undefined, reflushAbilityCallBack, foreverPeriodic);
    // TimeController.getInstance().startTimer({time: 1, opt: reflushAbilityTimerOpt});

    // const reflushBossCallBack = function () {
    //
    // }
    // const reflushBossTimerOpt = new TimeControllerOpt(undefined, reflushBossCallBack, foreverPeriodic);
    // TimeController.getInstance().startTimer({time: 0.1, opt: reflushBossTimerOpt});


    const interval = 0.1
    const subCoolBack = function () {
        PlayerFactory.getInstance().mapAllNotEndPlayingPlayer(
            (player) => {
                // const hero = GlobalEnv.getHero(player);
                // AbilityController.getInstance().reflushAbilityCool(hero, interval);
                const box = GlobalEnv.getBox(player);
                AbilityController.getInstance().reflushAbilityCool(box, interval);

                TaskController.getInstance().reflushTaskTime(player, interval);

                const unitArr = UnitController.getInstance().getCombinationUnitArr(player);
                for (let i = 0; i < unitArr.length; i ++ ) {
                    const unit = unitArr[i]
                    if (unit) {
                        AbilityController.getInstance().reflushAbilityCool(unit, interval);
                    }
                }

                UnitController.getInstance().reflushMoveTime(player, interval)
            }
        )
    }
    const subCoolOpt = new TimeControllerOpt(undefined, subCoolBack, foreverPeriodic);
    TimeController.getInstance().startTimer({time: interval, opt: subCoolOpt});


    // 任务完成与单位属性自动计算
    const caluBack = function () {
        PlayerFactory.getInstance().mapAllNotEndPlayingPlayer(
            (player) => {
                TaskController.getInstance().checkTasksFinsh(player);
            }
        )

        // 刷新属性机制
        AbilityController.getInstance().reflushAbilityAttributes();
        AbilityController.getInstance().reflushAbilityLocks();

        PlayerFactory.getInstance().mapAllPlayer(
            (player: PlayerModel) => {
                UnitController.getInstance().reflushFightTime(player);
            }
        )

        // 宠物数据更新
        PlayerFactory.getInstance().mapAllNotEndPlayingPlayer(
            (player) => {
                const hero = GlobalEnv.getHero(player);
                // 每秒属性增长
                if (hero?.isValid()) {
                    reflushHeroInfo(player, hero);
                    UnitController.getInstance().lifeAndMagicRecovery(hero);
                }

                let len = Configer.getConfig(ConfigKey.maxPetNum);
                for (let i = 0; i < len; i ++ ) {
                    const petInfo: UnitJson = player.data[PlayerDataKey.petInfo][i];
                    const pet: UnitModel = player.data[PlayerDataKey.pet][i];
                    if (pet?.isValid()) {
                        reflushPetInfo(player, pet, petInfo);
                        UnitController.getInstance().lifeAndMagicRecovery(pet);
                    }
                }
            }
        )

        // 从需要更新属性的单位的缓存中更新属性
        UnitController.getInstance().clearCaluTask();
    }
    const timerOpt = new TimeControllerOpt(undefined, caluBack, foreverPeriodic);
    TimeController.getInstance().startTimer({time: 1, opt: timerOpt});

    // 保存玩家英雄与全局属性
    const saveTaskCallBack = function () {
        PlayerFactory.getInstance().mapAllNotEndPlayingPlayer(
            (player) => {
                // 存档
                const hero = GlobalEnv.getHero(player);
                if (hero?.isValid()) {
                    StoreController.getInstance().addStoreTask(player, ControllerNo.UnitController);
                    StoreController.getInstance().addStoreTask(player, ControllerNo.StoreController);
                    StoreController.getInstance().addStoreTask(player, ControllerNo.AbilityController);
                }
           }
        )
    }
    const saveTaskTimerOpt = new TimeControllerOpt(undefined, saveTaskCallBack, foreverPeriodic);
    TimeController.getInstance().startTimer({time: 1, opt: saveTaskTimerOpt});


    const saveCallBack = function () {
        if (GlobalEnv.bStart) {
        } else {
            return;
        }
        PlayerFactory.getInstance().mapAllNotEndPlayingPlayer(
            (player) => {
                
                if (player.data[PlayerDataKey.bCheat]) {
                    TaskController.getInstance().toLose(player);
                    return;
                }

                const isBeLose = GlobalEnv.getCheckLose(player);
                if (isBeLose) {
                } else {
                    checkLose(TaskController.getInstance().toLose, player);
                }

                checkWin(TaskController.getInstance().toWin, player);

                // 存档
                const hero = GlobalEnv.getHero(player);
                if (hero) {
                    const level = hero.level;
                    const storeLevel = Configer.getConfig(ConfigKey.storeLevel);
                    if (level >= storeLevel) {
                        StoreController.getInstance().clearStoreTask(player);
                    }
                }
            }
        )
    }
    const saveTimerOpt = new TimeControllerOpt(undefined, saveCallBack, foreverPeriodic);
    TimeController.getInstance().startTimer({time: 1, opt: saveTimerOpt});

    // 关于宠物巡逻
    const petPatro = Configer.getConfig(ConfigKey.petPatro);
    if (!CodeUtil.isNullOrZero(petPatro)) {
        const patroCallBack = function () {
            PlayerFactory.getInstance().mapAllNotEndPlayingPlayer(
                (player) => {
                    toPatro(player);
                })
        }
        const patroTimerOpt = new TimeControllerOpt(undefined, patroCallBack, foreverPeriodic);
        TimeController.getInstance().startTimer({time: petPatro, opt: patroTimerOpt});
    }
}
function reflushShareBoss () {
    UnitController.getInstance().reflushShareBoss(false);
}

function toPatro (player: PlayerModel) {
    const patrol = player.data[PlayerDataKey.patro];
    const outRangeMove = Configer.getConfig(ConfigKey.outRangeMove);
    patrol.forEach(
        (pet: UnitModel, index, array) => {
            if (pet?.isAliveInBattle()) {
            } else {
                return;
            }
            const master = pet?.data[UnitDataKey.master];
            if (master?.isAliveInBattle()) {
            } else {
                return;
            }
            const probability = player.getRandomInt(0, 100);
            const patroProbability = 90;
            if (probability > patroProbability) {
                return;
            }
            const patrolRange = Configer.getConfig(ConfigKey.patrolRange) as number;
            const ownerPlayer = PlayerFactory.getInstance().getUnitOwner(pet);
            if (ownerPlayer === player) {
            } else {
                return;
            }
            const delay = patrolRange;
            // 大于二倍的巡逻距离时  使用跟随
            let maxDelay = delay * 2;

            const petLoc = pet.loc;
            const heroLoc = master.loc;
            const heroX = heroLoc.x;
            const heroY = heroLoc.y;
            const petX = petLoc.x;
            const petY = petLoc.y;
            const distanceX = MathUtil.abs(petX - heroX);
            const distanceY = MathUtil.abs(petY - heroY);
            if (!CodeUtil.isNullOrZero(outRangeMove)) {
                if (distanceX > outRangeMove || distanceY > outRangeMove) {
                    player.moveUnit(pet, heroLoc, false);
                    return;
                }
            }
            if (distanceX > maxDelay || distanceY > maxDelay) {
                pet.issueOrderAt(OrderStr.move, heroLoc)
            } else {
                const xRandom = player.getRandomReal(-delay, delay);
                const yRandom = player.getRandomReal(-delay, delay);
                const newX = heroX + xRandom;
                const newY = heroY + yRandom;
                const newLoc = new LocModel(newX, newY);
                pet.issueOrderAt(OrderStr.attack, newLoc)
            }
        }
    )

}

function reflushUIPanelSlow () {
    PlayerFactory.getInstance().mapAllPlayer(
        (player) => {
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.petBar, { }), player, OptType.reflush);
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.damageButton, { }), player, OptType.reflush);
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.multiBoradBar, { }), player, OptType.reflush);
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.chatBar, { }), player, OptType.reflush);
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.petBar, { }), player, OptType.reflush);
            // AbilityUtil.reflushSelectedUI(player)
        }
    )
}

function reflushUIPanelFast () {
    PlayerFactory.getInstance().mapAllPlayer(
        (player) => {
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.bossLifeBar, { }), player, OptType.reflush);
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.toastWheelBar, { }), player, OptType.reflush);
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.smallAttrBar, { }), player, OptType.reflush);
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.avatarBar, { }), player, OptType.reflush);
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.skillBar, { }), player, OptType.reflush);
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.itemBar, { }), player, OptType.reflush);
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.unitShopBar, { }), player, OptType.reflush);
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.topBar, { }), player, OptType.reflush);
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.equipBar, { }), player, OptType.reflush);
            GuiController.getInstance().showGui(new GuiControllerOpt(GuiId.buffBar, { }), player, OptType.reflush);
            // AbilityUtil.reflushSelectedUI(player)
        }
    )
}
function reflushHeroInfo (player: PlayerModel, hero: UnitModel) {
    const resumeTime = hero.data[UnitDataKey.resumeTime];
    const resumeTypes: ResumeType[] = Configer.getConfig(ConfigKey.resumeTypes);
    const isAutoResume = CodeUtil.inArr(resumeTypes, ResumeType.autoResume);
    if (isAutoResume) {
        if (!CodeUtil.isNullOrZero(resumeTime) && resumeTime > 0) {
            hero.data[UnitDataKey.resumeTime] = resumeTime - 1;
        } else if (resumeTime === 0) {
            UnitController.getInstance().resumeHero(player)
        }
    }
}

function reflushPetInfo (player: PlayerModel, pet: UnitModel, petInfo: UnitJson) {
    const oldExp = petInfo.e;
    const newExp = pet.experience;
    // const oldStr = petInfo.s;
    // const oldAgi = petInfo.a;
    // const oldInt = petInfo.i;
    // let str = Util.getTargetAttributeValueByNotHero(pet, AttributeEnum.strength, false);
    // let agi = Util.getTargetAttributeValueByNotHero(pet, AttributeEnum.agile, false);
    // let int = Util.getTargetAttributeValueByNotHero(pet, AttributeEnum.intellect, false);
    // str = Math.round(str);
    // agi = Math.round(agi);
    // int = Math.round(int);
    if (oldExp !== newExp) {
        petInfo.e = newExp;
    }

    const resumeTime = pet.data[UnitDataKey.resumeTime];
    if (!CodeUtil.isNullOrZero(resumeTime)) {
        pet.data[UnitDataKey.resumeTime] = resumeTime - 1;
    } else if (resumeTime === 0) {
        UnitController.getInstance().resumePet(player, pet)
    }
    // if (oldStr !== str) {
    //     petInfo.s = str;
    // }
    // if (oldAgi !== agi) {
    //     petInfo.a = agi;
    // }
    // if (oldInt !== int) {
    //     petInfo.i = int;
    // }
}

function checkLose(fun: (player: PlayerModel) => void, player: PlayerModel): any {
    let checkLoseTime: number = Configer.getConfig(ConfigKey.checkLoseTime);

    const difficult = GlobalEnv.difficult;
    const diffData = DataRouterUtil.getDifficultData(difficult);
    const checkGameLoseStr = diffData.loseType;
    let checkGameLose: string[] = CodeUtil.getArrBySplit(checkGameLoseStr);
    GlobalEnv.setCheckLose(player, true);

    let isNoHero = false;
    let isMoreMonster = false;

    for (let i = 0; i < checkGameLose.length; i++) {
        const type = DataRouterUtil.getNumByArr(checkGameLose, i);
        if (type && type >= 0) {
            if (type === GameLoseType.moreMonster) {
                isMoreMonster = true;
            } else if (type === GameLoseType.noHero) {
                isNoHero = true;
            }
        }
    }


    let checkFuns: ((player: PlayerModel) => boolean)[] = [];
    let str;
    if (isNoHero) {
        const checkFun = (player: PlayerModel) => {
            let isLose = true
            PlayerFactory.getInstance().mapAllNotEndPlayingPlayer(
                (player: PlayerModel) => {
                    const hero = GlobalEnv.getHero(player);
                    const isValid = hero?.isAlive();
                    if (isValid) {
                        isLose = false;
                    }
                }
            )
            str = `所有玩家阵亡，${checkLoseTime}秒后游戏失败！`;
            return isLose
        }
        checkFuns.push(checkFun);
    }
    if (isMoreMonster) {
        const checkFun = () => {
            let isLose = false
            const monsterNum = GlobalEnv.getAllAttackMonsterNum();
            const maxNum = GlobalEnv.getAllMaxAttackMonsterNum();
            if (monsterNum >= maxNum) {
                isLose = true;
                str = `当前怪物数超过${maxNum}只，${checkLoseTime}秒后游戏失败！`;
            }
            return isLose
        }
        checkFuns.push(checkFun);
    }

    const checkFun = (player: PlayerModel) => {
        checkLoseTime = 0;
        let isLose = GlobalEnv.getBeLose(player);
        return isLose;
    }
    checkFuns.push(checkFun);

    const loseCallBack = () => {
        let isLose = false;
        for (let i = 0; i < checkFuns.length; i++) {
            const checkFun = checkFuns[i];
            const ret = checkFun(player);
            if (ret) {
                isLose = true;
                break;
            }
        }
        if (isLose) {
            if (checkLoseTime === 0) {
                fun(player);
            } else {
                Logger.toastProduct(str, player)
                checkLoseTime = checkLoseTime - 1;
                const existenceOpt = new TimeControllerOpt(undefined, loseCallBack, 1);
                TimeController.getInstance().startTimer({time: 1, opt: existenceOpt});
            }
        } else {
            GlobalEnv.setCheckLose(player, false);
        }
    }
    loseCallBack();
}

function checkWin(fun: (player: PlayerModel) => void, player: PlayerModel): any {

    const difficult = GlobalEnv.difficult;
    const diffData = DataRouterUtil.getDifficultData(difficult);
    const checkGameWinStr = diffData.winType;
    let checkGameWin: string[] = CodeUtil.getArrBySplit(checkGameWinStr);

    let isOnlyMe = false;

    for (let i = 0; i < checkGameWin.length; i++) {
        const type = DataRouterUtil.getNumByArr(checkGameWin, i);
        if (type && type >= 0) {
            if (type === GameWinType.onlyMe) {
                isOnlyMe = true;
            }
        }
    }

    let checkFuns: ((player: PlayerModel) => boolean)[] = [];

    // let checkFun: (player: PlayerModel) => boolean;
    if (isOnlyMe) {
        const checkFun = (player: PlayerModel) => {
            let bWin = true;
            PlayerFactory.getInstance().mapAllNotEndPlayingPlayer(
                (tempPlayer) => {
                    const bLose = GlobalEnv.getBeLose(tempPlayer);
                    if (bLose) {
                    } else {
                        if (player === tempPlayer) {
                        } else {
                            bWin = false;
                        }
                    }
                }
            )
            return bWin;
        }
        checkFuns.push(checkFun);
    }

    const checkFun = (player: PlayerModel) => {
        let beWin = GlobalEnv.getBeWin(player);
        return beWin;
    }
    checkFuns.push(checkFun);


    const winCallBack = () => {
        let isWin = false;
        for (let i = 0; i < checkFuns.length; i++) {
            const checkFun = checkFuns[i];
            const ret = checkFun(player);
            if (ret) {
                isWin = true;
                break;
            }
        }
        if (isWin) {
            fun(player);
        }
    }
    winCallBack();
}